Introduction

In this vignette we’ll focus on one of the more complicated features of scLANE: the usage of GEE models to identify dynamic genes when cells are grouped by some subject identity. The robust variance estimation available in GEE models allows us to make decisions about which genes are actually dynamic over pseudotime / latent time while accounting for intra-subject correlations between observations. The downsides are that the benefits of GEE models can be a little more difficult to explain to collaborators, and they take a little bit longer than GLMs to estimate. A refresher on what GEEs are and why they’re useful can be found here.

Libraries

library(dplyr)      # data manipulation
library(scran)      # single cell tools 
library(scLANE)     # differential expression over pseudotime
library(scater)     # single cell tools 
library(slingshot)  # pseudotime estimation

Data

First we’ll load in the lung tumor data from Zilionis et al (2019), and subset to only include tumor neutrophils. The authors found 5 continuous tumor neutrophil subsets in their analysis, and we’re interested in determining which genes drive subset-to-subset differentiation. The data were collected from 7 different patients, and thus the usage of GEE models is warranted in order to properly estimate within-patient gene expression correlations. Lastly, we’ll subset the object to only include genes that are expressed in at least 5 cells.

lung <- scRNAseq::ZilionisLungData(which = "human", filter = TRUE)
lung <- lung[, stringr::str_detect(lung$`Major cell type`, "tNeutrophils")]
lung <- lung[which(rowSums(counts(lung) > 0) >= 5), ]

Preprocessing

First we’ll preprocess the data in the typical way. We see that the neutrophils fall into 5 clusters, and that there is one odd outlier group of cells near the top of the UMAP plot. In addition, there is a decent amount of intra- and inter-patient variability. The cluster labels are not solely reflective of the cell subtypes, and seem to be driven by both patient identity as well as cell subtype.

lung <- logNormCounts(lung)
var_decomp <- modelGeneVar(lung)
top2k_hvgs <- getTopHVGs(var_decomp, n = 2000)
lung <- runPCA(lung, subset_row = top2k_hvgs)
reducedDim(lung, "PCAsub") <- reducedDim(lung, "PCA")[, 1:10, drop = FALSE]
lung <- runUMAP(lung, dimred = "PCAsub", n_dimred = 1:10)
g <- buildSNNGraph(lung, use.dimred = "PCAsub", k = 20)
clusters <- igraph::cluster_louvain(graph = g)$membership
colLabels(lung) <- factor(clusters)
plotUMAP(lung, colour_by = "label")

plotUMAP(lung, colour_by = "Patient")

plotUMAP(lung, colour_by = "Minor subset")

Estimating Pseudotime

We’ll use slingshot to estimate a pseudotime value for each cell. In this case, we see only one pseudotime lineage.

scl_lineage <- getLineages(reducedDim(lung, "PCAsub"), clusterLabels = clusters)
scl_crv <- getCurves(scl_lineage)
scl_cell_weights <- slingCurveWeights(scl_crv)
scl_pt <- slingPseudotime(scl_crv)
pt_df <- as.data.frame(scl_pt) %>% 
         mutate(across(everything(), function(x) x / max(x, na.rm = TRUE)))

Running scLANE

Global Test

We’re going to run scLANE solely on the top 100 most highly variable genes. This is for both computational quickness & in order to get interesting results (highly variable \(\implies\) dynamic, usually), as this is a just a tutorial. Note that we need to provide a (sorted) vector of subject IDs as well as a working correlation structure. In this case we opt for the exchangeable (AKA compound symmetry) structure, as it stands to reason that within-subject cells will have similar correlations.

lung_counts <- as.matrix(t(lung@assays@data$counts))[, top2k_hvgs[1:100]]
gene_stats <- testDynamic(expr.mat = lung_counts, 
                          pt = pt_df, 
                          is.gee = TRUE, 
                          id.vec = lung$Patient, 
                          cor.structure = "exchangeable", 
                          n.potential.basis.fns = 4, 
                          parallel.exec = TRUE, 
                          n.cores = 6, 
                          track.time = TRUE)
[1] "testDynamic evaluated 100 genes with 2 lineages apiece in 1.727 hours"

Let’s check out the results of the global differential expression test.

getResultsDE(gene_stats) %>% 
  select(-contains("LogLik"), -contains("Dev")) %>%  # not relevant to GEEs
  arrange(Gene, Lineage) %>% 
  slice_head(n = 10) %>% 
  kableExtra::kbl(digits = 5, 
                  align = "c", 
                  booktabs = TRUE, 
                  caption = "Lineage-level dynamic test", 
                  col.names = c("Gene", "Lineage", "Test Stat.", "P-value", "Test Stat. Type", "Test Notes", 
                                "Model Status", "Adj. P-value", "Gene Dynamic over Lineage", "Gene Dynamic")) %>% 
  kableExtra::kable_paper("hover", full_width = FALSE)
Lineage-level dynamic test
Gene Lineage Test Stat. P-value Test Stat. Type Test Notes Model Status Adj. P-value Gene Dynamic over Lineage Gene Dynamic
AC245128.3 A NA NA Wald NA MARGE model error, null model OK NA 0 1
AC245128.3 B 14317.49413 0.00000 Wald NA MARGE model OK, null model OK 0.0000 1 1
ACSL1 A NA NA Wald NA MARGE model error, null model OK NA 0 0
ACSL1 B 15.06179 0.00176 Wald NA MARGE model OK, null model OK 0.3088 0 0
ACTB A 1830.90455 0.00000 Wald NA MARGE model OK, null model OK 0.0000 1 1
ACTB B 816.06553 0.00000 Wald NA MARGE model OK, null model OK 0.0000 1 1
ACTG1 A NA NA Wald NA MARGE model error, null model OK NA 0 0
ACTG1 B 8.46577 0.01451 Wald NA MARGE model OK, null model OK 1.0000 0 0
ADM A 230.24808 0.00000 Wald NA MARGE model OK, null model OK 0.0000 1 1
ADM B 826.35930 0.00000 Wald NA MARGE model OK, null model OK 0.0000 1 1

Slope Test

Next we can run the slope test to identify over which pseudotime intervals gene expression changes significantly.

testSlope(test.dyn.results = gene_stats) %>% 
  slice_head(n = 10) %>% 
  kableExtra::kbl(digits = 5, 
                  align = "c", 
                  booktabs = TRUE, 
                  caption = "Slope-level dynamic test", 
                  col.names = c("Gene", "Lineage", "Breakpoint", "Rounded Breakpoint", 
                                "Direction", "P-value", "Notes", "Adj. P-value", 
                                "Gene Dynamic over Lineage-Slope", "Gene Dynamic over Lineage", 
                                "Gene Dynamic")) %>% 
  kableExtra::kable_paper("hover", full_width = FALSE)
Slope-level dynamic test
Gene Lineage Breakpoint Rounded Breakpoint Direction P-value Notes Adj. P-value Gene Dynamic over Lineage-Slope Gene Dynamic over Lineage Gene Dynamic
AC245128.3 B 0.02320 0.0232 Right 0.00061 NA 0.16273 0 0 0
AC245128.3 1 NA NA NA NA MARGE model error, null model OK NA 0 0 0
ACSL1 B 0.02320 0.0232 Right 0.00136 NA 0.36125 0 0 0
ACSL1 B 0.75149 0.7515 Right 0.00012 NA 0.03160 0 0 0
ACSL1 1 NA NA NA NA MARGE model error, null model OK NA 0 0 0
ACTB B 0.02320 0.0232 Right 0.05586 NA 1.00000 0 0 1
ACTB A 0.37023 0.3702 Right 0.00000 NA 0.00000 1 1 1
ACTB A 0.37314 0.3731 Left 0.00000 NA 0.00000 1 1 1
ACTG1 B 0.02320 0.0232 Right 0.00552 NA 1.00000 0 0 0
ACTG1 1 NA NA NA NA MARGE model error, null model OK NA 0 0 0

Model Visualization

Lastly, we can plot the fitted models for a couple of the genes. In addition to the null (intercept-only) and MARGE models we can also compare to a GEE GLM with pseudotime as a covariate.

plotModels(test.dyn.res = gene_stats, 
           gene = "CXCL8", 
           pt = pt_df, 
           gene.counts = lung_counts, 
           is.gee = TRUE, 
           id.vec = lung$Patient, 
           cor.structure = "exchangeable")

plotModels(test.dyn.res = gene_stats, 
           gene = "RGS2", 
           pt = pt_df, 
           gene.counts = lung_counts, 
           is.gee = TRUE, 
           id.vec = lung$Patient, 
           cor.structure = "exchangeable")

Gene-level Analysis

Let’s cluster the genes based on their fitted values using hierarchical clustering with Ward’s linkage.

purrr::map(gene_stats, function(x) {
  if (stringr::str_detect(x$Lineage_A$Model_Status, "error")) {
    NA
  } else {
    x$Lineage_A$MARGE_Preds$marge_link_fit
  }
}) %>% 
  purrr::reduce(cbind) %>% 
  set_colnames(names(gene_stats)) %>% 
  #set_rownames(rownames(lung_counts)) %>% 
  janitor::remove_empty(which = "cols") -> fitted_vals
fitted_vals_pca <- prcomp(t(fitted_vals), center = TRUE, rank. = 10)$x
fitted_vals_clusts <- hclust(dist(fitted_vals_pca), method = "ward.D2")
ggdendro::ggdendrogram(fitted_vals_clusts) + 
  labs(title = "Heirarchical Clustering of Highly-Variable Genes") + 
  theme_classic(base_size = 14) + 
  theme(axis.text.x = element_text(angle = 90, size = 8), 
        plot.title = element_text(hjust = 0.5), 
        axis.text.y = element_blank(), 
        axis.title = element_blank())

Session Info

sessioninfo::session_info()
─ Session info ───────────────────────────────────────────────────────────────
 setting  value                       
 version  R version 4.0.4 (2021-02-15)
 os       macOS Big Sur 10.16         
 system   x86_64, darwin17.0          
 ui       X11                         
 language (EN)                        
 collate  en_US.UTF-8                 
 ctype    en_US.UTF-8                 
 tz       America/New_York            
 date     2022-05-08                  

─ Packages ───────────────────────────────────────────────────────────────────
 package                * version   date       lib source        
 AnnotationDbi            1.52.0    2020-10-27 [1] Bioconductor  
 AnnotationFilter         1.14.0    2020-10-27 [1] Bioconductor  
 AnnotationHub            2.22.0    2020-10-27 [1] Bioconductor  
 ape                      5.5       2021-04-25 [1] CRAN (R 4.0.2)
 askpass                  1.1       2019-01-13 [1] CRAN (R 4.0.2)
 assertthat               0.2.1     2019-03-21 [1] CRAN (R 4.0.2)
 backports                1.2.1     2020-12-09 [1] CRAN (R 4.0.2)
 beachmat                 2.6.4     2020-12-20 [1] Bioconductor  
 beeswarm                 0.3.1     2021-03-07 [1] CRAN (R 4.0.2)
 bigassertr               0.1.5     2021-07-08 [1] CRAN (R 4.0.2)
 bigparallelr             0.3.1     2021-02-02 [1] CRAN (R 4.0.2)
 bigstatsr                1.5.1     2021-04-05 [1] CRAN (R 4.0.2)
 Biobase                * 2.50.0    2020-10-27 [1] Bioconductor  
 BiocFileCache            1.14.0    2020-10-27 [1] Bioconductor  
 BiocGenerics           * 0.36.0    2020-10-27 [1] Bioconductor  
 BiocManager              1.30.12   2021-03-28 [1] CRAN (R 4.0.2)
 BiocNeighbors            1.8.2     2020-12-07 [1] Bioconductor  
 BiocParallel             1.24.1    2020-11-06 [1] Bioconductor  
 BiocSingular             1.6.0     2020-10-27 [1] Bioconductor  
 BiocVersion              3.12.0    2020-05-14 [1] Bioconductor  
 biomaRt                  2.46.3    2021-02-11 [1] Bioconductor  
 Biostrings               2.58.0    2020-10-27 [1] Bioconductor  
 bit                      4.0.4     2020-08-04 [1] CRAN (R 4.0.2)
 bit64                    4.0.5     2020-08-30 [1] CRAN (R 4.0.2)
 bitops                   1.0-6     2013-08-17 [1] CRAN (R 4.0.2)
 blob                     1.2.1     2020-01-20 [1] CRAN (R 4.0.2)
 bluster                  1.0.0     2020-10-27 [1] Bioconductor  
 broom                    0.7.12    2022-01-28 [1] CRAN (R 4.0.5)
 bslib                    0.2.4     2021-01-25 [1] CRAN (R 4.0.2)
 cachem                   1.0.4     2021-02-13 [1] CRAN (R 4.0.2)
 cli                      3.1.1     2022-01-20 [1] CRAN (R 4.0.5)
 codetools                0.2-18    2020-11-04 [1] CRAN (R 4.0.4)
 colorspace               2.0-0     2020-11-11 [1] CRAN (R 4.0.2)
 cowplot                  1.1.1     2020-12-30 [1] CRAN (R 4.0.2)
 crayon                   1.4.1     2021-02-08 [1] CRAN (R 4.0.2)
 curl                     4.3       2019-12-02 [1] CRAN (R 4.0.1)
 DBI                      1.1.1     2021-01-15 [1] CRAN (R 4.0.2)
 dbplyr                   2.1.1     2021-04-06 [1] CRAN (R 4.0.2)
 DelayedArray             0.16.3    2021-03-24 [1] Bioconductor  
 DelayedMatrixStats       1.12.3    2021-02-03 [1] Bioconductor  
 digest                   0.6.27    2020-10-24 [1] CRAN (R 4.0.2)
 doParallel               1.0.16    2020-10-16 [1] CRAN (R 4.0.2)
 dplyr                  * 1.0.7     2021-06-18 [1] CRAN (R 4.0.2)
 dqrng                    0.2.1     2019-05-17 [1] CRAN (R 4.0.2)
 edgeR                    3.32.1    2021-01-14 [1] Bioconductor  
 ellipsis                 0.3.2     2021-04-29 [1] CRAN (R 4.0.2)
 ensembldb                2.14.0    2020-10-27 [1] Bioconductor  
 evaluate                 0.14      2019-05-28 [1] CRAN (R 4.0.1)
 ExperimentHub            1.16.0    2020-10-27 [1] Bioconductor  
 fansi                    0.4.2     2021-01-15 [1] CRAN (R 4.0.2)
 farver                   2.1.0     2021-02-28 [1] CRAN (R 4.0.3)
 fastmap                  1.1.0     2021-01-25 [1] CRAN (R 4.0.2)
 flock                    0.7       2016-11-12 [1] CRAN (R 4.0.2)
 FNN                      1.1.3     2019-02-15 [1] CRAN (R 4.0.2)
 foreach                  1.5.1     2020-10-15 [1] CRAN (R 4.0.2)
 gamlss                   5.3-4     2021-03-31 [1] CRAN (R 4.0.2)
 gamlss.data              6.0-1     2021-03-18 [1] CRAN (R 4.0.2)
 gamlss.dist              5.3-2     2021-03-09 [1] CRAN (R 4.0.2)
 geeM                     0.10.1    2018-06-18 [1] CRAN (R 4.0.2)
 generics                 0.1.2     2022-01-31 [1] CRAN (R 4.0.5)
 GenomeInfoDb           * 1.26.7    2021-04-08 [1] Bioconductor  
 GenomeInfoDbData         1.2.4     2021-01-12 [1] Bioconductor  
 GenomicAlignments        1.26.0    2020-10-27 [1] Bioconductor  
 GenomicFeatures          1.42.3    2021-04-04 [1] Bioconductor  
 GenomicRanges          * 1.42.0    2020-10-27 [1] Bioconductor  
 ggbeeswarm               0.6.0     2017-08-07 [1] CRAN (R 4.0.2)
 ggdendro                 0.1.22    2020-09-13 [1] CRAN (R 4.0.2)
 ggplot2                * 3.3.5     2021-06-25 [1] CRAN (R 4.0.2)
 glm2                     1.2.1     2018-08-11 [1] CRAN (R 4.0.2)
 glue                     1.4.2     2020-08-27 [1] CRAN (R 4.0.2)
 gridExtra                2.3       2017-09-09 [1] CRAN (R 4.0.2)
 gtable                   0.3.0     2019-03-25 [1] CRAN (R 4.0.2)
 highr                    0.8       2019-03-20 [1] CRAN (R 4.0.2)
 hms                      1.0.0     2021-01-13 [1] CRAN (R 4.0.2)
 htmltools                0.5.1.1   2021-01-22 [1] CRAN (R 4.0.2)
 httpuv                   1.5.5     2021-01-13 [1] CRAN (R 4.0.2)
 httr                     1.4.2     2020-07-20 [1] CRAN (R 4.0.2)
 igraph                   1.3.1     2022-04-20 [1] CRAN (R 4.0.4)
 interactiveDisplayBase   1.28.0    2020-10-27 [1] Bioconductor  
 IRanges                * 2.24.1    2020-12-12 [1] Bioconductor  
 irlba                    2.3.3     2019-02-05 [1] CRAN (R 4.0.2)
 iterators                1.0.13    2020-10-15 [1] CRAN (R 4.0.2)
 janitor                  2.1.0     2021-01-05 [1] CRAN (R 4.0.2)
 jquerylib                0.1.3     2020-12-17 [1] CRAN (R 4.0.2)
 jsonlite                 1.7.2     2020-12-09 [1] CRAN (R 4.0.2)
 kableExtra               1.3.4     2021-02-20 [1] CRAN (R 4.0.2)
 knitr                    1.37      2021-12-16 [1] CRAN (R 4.0.2)
 labeling                 0.4.2     2020-10-20 [1] CRAN (R 4.0.2)
 later                    1.1.0.1   2020-06-05 [1] CRAN (R 4.0.2)
 lattice                  0.20-41   2020-04-02 [1] CRAN (R 4.0.4)
 lazyeval                 0.2.2     2019-03-15 [1] CRAN (R 4.0.2)
 lifecycle                1.0.0     2021-02-15 [1] CRAN (R 4.0.2)
 limma                    3.46.0    2020-10-27 [1] Bioconductor  
 locfit                   1.5-9.4   2020-03-25 [1] CRAN (R 4.0.2)
 lubridate                1.7.10    2021-02-26 [1] CRAN (R 4.0.2)
 magrittr               * 2.0.1     2020-11-17 [1] CRAN (R 4.0.2)
 MASS                     7.3-53.1  2021-02-12 [1] CRAN (R 4.0.2)
 Matrix                   1.3-2     2021-01-06 [1] CRAN (R 4.0.4)
 MatrixGenerics         * 1.2.1     2021-01-30 [1] Bioconductor  
 matrixStats            * 0.58.0    2021-01-29 [1] CRAN (R 4.0.2)
 memoise                  2.0.0     2021-01-26 [1] CRAN (R 4.0.2)
 mgcv                     1.8-36    2021-06-01 [1] CRAN (R 4.0.2)
 mime                     0.10      2021-02-13 [1] CRAN (R 4.0.2)
 munsell                  0.5.0     2018-06-12 [1] CRAN (R 4.0.2)
 mvabund                  4.1.12    2021-05-28 [1] CRAN (R 4.0.2)
 nlme                     3.1-152   2021-02-04 [1] CRAN (R 4.0.4)
 openssl                  1.4.3     2020-09-18 [1] CRAN (R 4.0.2)
 pillar                   1.6.5     2022-01-25 [1] CRAN (R 4.0.5)
 pkgconfig                2.0.3     2019-09-22 [1] CRAN (R 4.0.2)
 prettyunits              1.1.1     2020-01-24 [1] CRAN (R 4.0.2)
 princurve              * 2.1.6     2021-01-18 [1] CRAN (R 4.0.2)
 progress                 1.2.2     2019-05-16 [1] CRAN (R 4.0.2)
 promises                 1.2.0.1   2021-02-11 [1] CRAN (R 4.0.2)
 ProtGenerics             1.22.0    2020-10-27 [1] Bioconductor  
 ps                       1.6.0     2021-02-28 [1] CRAN (R 4.0.3)
 purrr                    0.3.4     2020-04-17 [1] CRAN (R 4.0.2)
 R6                       2.5.0     2020-10-28 [1] CRAN (R 4.0.2)
 rappdirs                 0.3.3     2021-01-31 [1] CRAN (R 4.0.2)
 Rcpp                     1.0.7     2021-07-07 [1] CRAN (R 4.0.2)
 RcppEigen                0.3.3.9.1 2020-12-17 [1] CRAN (R 4.0.2)
 RCurl                    1.98-1.3  2021-03-16 [1] CRAN (R 4.0.2)
 rlang                    1.0.0     2022-01-26 [1] CRAN (R 4.0.5)
 rmarkdown                2.11      2021-09-14 [1] CRAN (R 4.0.4)
 Rsamtools                2.6.0     2020-10-27 [1] Bioconductor  
 RSpectra                 0.16-0    2019-12-01 [1] CRAN (R 4.0.2)
 RSQLite                  2.2.6     2021-04-11 [1] CRAN (R 4.0.2)
 rstudioapi               0.13      2020-11-12 [1] CRAN (R 4.0.2)
 rsvd                     1.0.3     2020-02-17 [1] CRAN (R 4.0.2)
 rtracklayer              1.50.0    2020-10-27 [1] Bioconductor  
 rvest                    1.0.0     2021-03-09 [1] CRAN (R 4.0.2)
 S4Vectors              * 0.28.1    2020-12-09 [1] Bioconductor  
 sass                     0.3.1     2021-01-24 [1] CRAN (R 4.0.2)
 scales                   1.1.1     2020-05-11 [1] CRAN (R 4.0.2)
 scater                 * 1.18.6    2021-02-26 [1] Bioconductor  
 scLANE                 * 0.3.1     2022-05-08 [1] local         
 scran                  * 1.18.7    2021-04-16 [1] Bioconductor  
 scRNAseq               * 2.4.0     2020-11-09 [1] Bioconductor  
 scuttle                  1.0.4     2020-12-17 [1] Bioconductor  
 sessioninfo              1.1.1     2018-11-05 [1] CRAN (R 4.0.2)
 shiny                    1.6.0     2021-01-25 [1] CRAN (R 4.0.2)
 SingleCellExperiment   * 1.12.0    2020-10-27 [1] Bioconductor  
 slingshot              * 1.8.0     2020-10-27 [1] Bioconductor  
 snakecase                0.11.0    2019-05-25 [1] CRAN (R 4.0.2)
 sparseMatrixStats        1.2.1     2021-02-02 [1] Bioconductor  
 statmod                  1.4.35    2020-10-19 [1] CRAN (R 4.0.2)
 stringi                  1.5.3     2020-09-09 [1] CRAN (R 4.0.2)
 stringr                  1.4.0     2019-02-10 [1] CRAN (R 4.0.2)
 SummarizedExperiment   * 1.20.0    2020-10-27 [1] Bioconductor  
 survival                 3.2-10    2021-03-16 [1] CRAN (R 4.0.2)
 svglite                  2.0.0     2021-02-20 [1] CRAN (R 4.0.2)
 systemfonts              1.0.1     2021-02-09 [1] CRAN (R 4.0.2)
 tibble                   3.1.6     2021-11-07 [1] CRAN (R 4.0.2)
 tidyr                    1.1.4     2021-09-27 [1] CRAN (R 4.0.2)
 tidyselect               1.1.0     2020-05-11 [1] CRAN (R 4.0.2)
 tweedie                  2.3.3     2021-01-20 [1] CRAN (R 4.0.2)
 utf8                     1.2.1     2021-03-12 [1] CRAN (R 4.0.2)
 uwot                     0.1.10    2020-12-15 [1] CRAN (R 4.0.2)
 vctrs                    0.3.8     2021-04-29 [1] CRAN (R 4.0.2)
 vipor                    0.4.5     2017-03-22 [1] CRAN (R 4.0.2)
 viridis                  0.6.0     2021-04-15 [1] CRAN (R 4.0.4)
 viridisLite              0.4.0     2021-04-13 [1] CRAN (R 4.0.2)
 webshot                  0.5.2     2019-11-22 [1] CRAN (R 4.0.2)
 withr                    2.4.3     2021-11-30 [1] CRAN (R 4.0.2)
 xfun                     0.29      2021-12-14 [1] CRAN (R 4.0.2)
 XML                      3.99-0.6  2021-03-16 [1] CRAN (R 4.0.2)
 xml2                     1.3.2     2020-04-23 [1] CRAN (R 4.0.2)
 xtable                   1.8-4     2019-04-21 [1] CRAN (R 4.0.2)
 XVector                  0.30.0    2020-10-28 [1] Bioconductor  
 yaml                     2.2.1     2020-02-01 [1] CRAN (R 4.0.2)
 zlibbioc                 1.36.0    2020-10-28 [1] Bioconductor  

[1] /Library/Frameworks/R.framework/Versions/4.0/Resources/library
LS0tCnRpdGxlOiAiSWRlbnRpZnlpbmcgRHluYW1pYyBHZW5lcyB3aXRoIEdlbmVyYWxpemVkIEVzdGltYXRpbmcgRXF1YXRpb25zIGluIGBzY0xBTkVgIgpzdWJ0aXRsZTogIlVuaXZlcnNpdHkgb2YgRmxvcmlkYSAtIERlcHQuIG9mIEJpb3N0YXRpc3RpY3MgLSBCYWNoZXIgR3JvdXAiCmF1dGhvcjogIkphY2sgTGVhcnkiCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICB0aGVtZTogeWV0aQogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgY29kZV9mb2xkaW5nOiBzaG93CiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDoKICAgICAgY29sbHBhc2VkOiBmYWxzZQogICAgZGZfcHJpbnQ6IGthYmxlCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgICAgICBjb21tZW50ID0gTkEsIAogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IEZBTFNFLCAKICAgICAgICAgICAgICAgICAgICAgIHdhcm5pbmcgPSBGQUxTRSwgCiAgICAgICAgICAgICAgICAgICAgICBmaWcuYWxpZ24gPSAiY2VudGVyIikKc2V0LnNlZWQoMzEyKSAgIyBsdWNreSBzZWVkCmBgYAoKIyBJbnRyb2R1Y3Rpb24gCgpJbiB0aGlzIHZpZ25ldHRlIHdlJ2xsIGZvY3VzIG9uIG9uZSBvZiB0aGUgbW9yZSBjb21wbGljYXRlZCBmZWF0dXJlcyBvZiBgc2NMQU5FYDogdGhlIHVzYWdlIG9mIEdFRSBtb2RlbHMgdG8gaWRlbnRpZnkgZHluYW1pYyBnZW5lcyB3aGVuIGNlbGxzIGFyZSBncm91cGVkIGJ5IHNvbWUgc3ViamVjdCBpZGVudGl0eS4gVGhlIHJvYnVzdCB2YXJpYW5jZSBlc3RpbWF0aW9uIGF2YWlsYWJsZSBpbiBHRUUgbW9kZWxzIGFsbG93cyB1cyB0byBtYWtlIGRlY2lzaW9ucyBhYm91dCB3aGljaCBnZW5lcyBhcmUgYWN0dWFsbHkgZHluYW1pYyBvdmVyIHBzZXVkb3RpbWUgLyBsYXRlbnQgdGltZSB3aGlsZSBhY2NvdW50aW5nIGZvciBpbnRyYS1zdWJqZWN0IGNvcnJlbGF0aW9ucyBiZXR3ZWVuIG9ic2VydmF0aW9ucy4gVGhlIGRvd25zaWRlcyBhcmUgdGhhdCB0aGUgYmVuZWZpdHMgb2YgR0VFIG1vZGVscyBjYW4gYmUgYSBsaXR0bGUgbW9yZSBkaWZmaWN1bHQgdG8gZXhwbGFpbiB0byBjb2xsYWJvcmF0b3JzLCBhbmQgdGhleSB0YWtlIGEgbGl0dGxlIGJpdCBsb25nZXIgdGhhbiBHTE1zIHRvIGVzdGltYXRlLiBBIHJlZnJlc2hlciBvbiB3aGF0IEdFRXMgYXJlIGFuZCB3aHkgdGhleSdyZSB1c2VmdWwgY2FuIGJlIGZvdW5kIFtoZXJlXShodHRwczovL3d3dy5wdWJsaWNoZWFsdGguY29sdW1iaWEuZWR1L3Jlc2VhcmNoL3BvcHVsYXRpb24taGVhbHRoLW1ldGhvZHMvcmVwZWF0ZWQtbWVhc3VyZXMtYW5hbHlzaXMpLiAKCiMgTGlicmFyaWVzCgpgYGB7ciwgcmVzdWx0cz0naGlkZSd9CmxpYnJhcnkoZHBseXIpICAgICAgIyBkYXRhIG1hbmlwdWxhdGlvbgpsaWJyYXJ5KHNjcmFuKSAgICAgICMgc2luZ2xlIGNlbGwgdG9vbHMgCmxpYnJhcnkoc2NMQU5FKSAgICAgIyBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBvdmVyIHBzZXVkb3RpbWUKbGlicmFyeShzY2F0ZXIpICAgICAjIHNpbmdsZSBjZWxsIHRvb2xzIApsaWJyYXJ5KHNsaW5nc2hvdCkgICMgcHNldWRvdGltZSBlc3RpbWF0aW9uCmBgYAoKIyBEYXRhIAoKRmlyc3Qgd2UnbGwgbG9hZCBpbiB0aGUgbHVuZyB0dW1vciBkYXRhIGZyb20gW1ppbGlvbmlzICpldCBhbCogKDIwMTkpXShodHRwczovL3d3dy5uY2JpLm5sbS5uaWguZ292L3BtYy9hcnRpY2xlcy9QTUM2NjIwMDQ5LyksIGFuZCBzdWJzZXQgdG8gb25seSBpbmNsdWRlIHR1bW9yIG5ldXRyb3BoaWxzLiBUaGUgYXV0aG9ycyBmb3VuZCA1IGNvbnRpbnVvdXMgdHVtb3IgbmV1dHJvcGhpbCBzdWJzZXRzIGluIHRoZWlyIGFuYWx5c2lzLCBhbmQgd2UncmUgaW50ZXJlc3RlZCBpbiBkZXRlcm1pbmluZyB3aGljaCBnZW5lcyBkcml2ZSBzdWJzZXQtdG8tc3Vic2V0IGRpZmZlcmVudGlhdGlvbi4gVGhlIGRhdGEgd2VyZSBjb2xsZWN0ZWQgZnJvbSA3IGRpZmZlcmVudCBwYXRpZW50cywgYW5kIHRodXMgdGhlIHVzYWdlIG9mIEdFRSBtb2RlbHMgaXMgd2FycmFudGVkIGluIG9yZGVyIHRvIHByb3Blcmx5IGVzdGltYXRlIHdpdGhpbi1wYXRpZW50IGdlbmUgZXhwcmVzc2lvbiBjb3JyZWxhdGlvbnMuIExhc3RseSwgd2UnbGwgc3Vic2V0IHRoZSBvYmplY3QgdG8gb25seSBpbmNsdWRlIGdlbmVzIHRoYXQgYXJlIGV4cHJlc3NlZCBpbiBhdCBsZWFzdCA1IGNlbGxzLiAKCmBgYHtyfQpsdW5nIDwtIHNjUk5Bc2VxOjpaaWxpb25pc0x1bmdEYXRhKHdoaWNoID0gImh1bWFuIiwgZmlsdGVyID0gVFJVRSkKbHVuZyA8LSBsdW5nWywgc3RyaW5ncjo6c3RyX2RldGVjdChsdW5nJGBNYWpvciBjZWxsIHR5cGVgLCAidE5ldXRyb3BoaWxzIildCmx1bmcgPC0gbHVuZ1t3aGljaChyb3dTdW1zKGNvdW50cyhsdW5nKSA+IDApID49IDUpLCBdCmBgYAoKIyMgUHJlcHJvY2Vzc2luZwoKRmlyc3Qgd2UnbGwgcHJlcHJvY2VzcyB0aGUgZGF0YSBpbiB0aGUgdHlwaWNhbCB3YXkuIFdlIHNlZSB0aGF0IHRoZSBuZXV0cm9waGlscyBmYWxsIGludG8gNSBjbHVzdGVycywgYW5kIHRoYXQgdGhlcmUgaXMgb25lIG9kZCBvdXRsaWVyIGdyb3VwIG9mIGNlbGxzIG5lYXIgdGhlIHRvcCBvZiB0aGUgVU1BUCBwbG90LiBJbiBhZGRpdGlvbiwgdGhlcmUgaXMgYSBkZWNlbnQgYW1vdW50IG9mIGludHJhLSBhbmQgaW50ZXItcGF0aWVudCB2YXJpYWJpbGl0eS4gVGhlIGNsdXN0ZXIgbGFiZWxzIGFyZSBub3Qgc29sZWx5IHJlZmxlY3RpdmUgb2YgdGhlIGNlbGwgc3VidHlwZXMsIGFuZCBzZWVtIHRvIGJlIGRyaXZlbiBieSBib3RoIHBhdGllbnQgaWRlbnRpdHkgYXMgd2VsbCBhcyBjZWxsIHN1YnR5cGUuIAoKYGBge3J9Cmx1bmcgPC0gbG9nTm9ybUNvdW50cyhsdW5nKQp2YXJfZGVjb21wIDwtIG1vZGVsR2VuZVZhcihsdW5nKQp0b3Aya19odmdzIDwtIGdldFRvcEhWR3ModmFyX2RlY29tcCwgbiA9IDIwMDApCmx1bmcgPC0gcnVuUENBKGx1bmcsIHN1YnNldF9yb3cgPSB0b3Aya19odmdzKQpyZWR1Y2VkRGltKGx1bmcsICJQQ0FzdWIiKSA8LSByZWR1Y2VkRGltKGx1bmcsICJQQ0EiKVssIDE6MTAsIGRyb3AgPSBGQUxTRV0KbHVuZyA8LSBydW5VTUFQKGx1bmcsIGRpbXJlZCA9ICJQQ0FzdWIiLCBuX2RpbXJlZCA9IDE6MTApCmcgPC0gYnVpbGRTTk5HcmFwaChsdW5nLCB1c2UuZGltcmVkID0gIlBDQXN1YiIsIGsgPSAyMCkKY2x1c3RlcnMgPC0gaWdyYXBoOjpjbHVzdGVyX2xvdXZhaW4oZ3JhcGggPSBnKSRtZW1iZXJzaGlwCmNvbExhYmVscyhsdW5nKSA8LSBmYWN0b3IoY2x1c3RlcnMpCnBsb3RVTUFQKGx1bmcsIGNvbG91cl9ieSA9ICJsYWJlbCIpCnBsb3RVTUFQKGx1bmcsIGNvbG91cl9ieSA9ICJQYXRpZW50IikKcGxvdFVNQVAobHVuZywgY29sb3VyX2J5ID0gIk1pbm9yIHN1YnNldCIpCmBgYAoKIyMgRXN0aW1hdGluZyBQc2V1ZG90aW1lCgpXZSdsbCB1c2UgYHNsaW5nc2hvdGAgdG8gZXN0aW1hdGUgYSBwc2V1ZG90aW1lIHZhbHVlIGZvciBlYWNoIGNlbGwuIEluIHRoaXMgY2FzZSwgd2Ugc2VlIG9ubHkgb25lIHBzZXVkb3RpbWUgbGluZWFnZS4gCgpgYGB7cn0Kc2NsX2xpbmVhZ2UgPC0gZ2V0TGluZWFnZXMocmVkdWNlZERpbShsdW5nLCAiUENBc3ViIiksIGNsdXN0ZXJMYWJlbHMgPSBjbHVzdGVycykKc2NsX2NydiA8LSBnZXRDdXJ2ZXMoc2NsX2xpbmVhZ2UpCnNjbF9jZWxsX3dlaWdodHMgPC0gc2xpbmdDdXJ2ZVdlaWdodHMoc2NsX2NydikKc2NsX3B0IDwtIHNsaW5nUHNldWRvdGltZShzY2xfY3J2KQpwdF9kZiA8LSBhcy5kYXRhLmZyYW1lKHNjbF9wdCkgJT4lIAogICAgICAgICBtdXRhdGUoYWNyb3NzKGV2ZXJ5dGhpbmcoKSwgZnVuY3Rpb24oeCkgeCAvIG1heCh4LCBuYS5ybSA9IFRSVUUpKSkKYGBgCgojIFJ1bm5pbmcgYHNjTEFORWAgCgojIyBHbG9iYWwgVGVzdAoKV2UncmUgZ29pbmcgdG8gcnVuIGBzY0xBTkVgIHNvbGVseSBvbiB0aGUgdG9wIDEwMCBtb3N0IGhpZ2hseSB2YXJpYWJsZSBnZW5lcy4gVGhpcyBpcyBmb3IgYm90aCBjb21wdXRhdGlvbmFsIHF1aWNrbmVzcyAmIGluIG9yZGVyIHRvIGdldCBpbnRlcmVzdGluZyByZXN1bHRzIChoaWdobHkgdmFyaWFibGUgJFxpbXBsaWVzJCBkeW5hbWljLCB1c3VhbGx5KSwgYXMgdGhpcyBpcyBhIGp1c3QgYSB0dXRvcmlhbC4gTm90ZSB0aGF0IHdlIG5lZWQgdG8gcHJvdmlkZSBhIChzb3J0ZWQpIHZlY3RvciBvZiBzdWJqZWN0IElEcyBhcyB3ZWxsIGFzIGEgd29ya2luZyBjb3JyZWxhdGlvbiBzdHJ1Y3R1cmUuIEluIHRoaXMgY2FzZSB3ZSBvcHQgZm9yIHRoZSBleGNoYW5nZWFibGUgKEFLQSBjb21wb3VuZCBzeW1tZXRyeSkgc3RydWN0dXJlLCBhcyBpdCBzdGFuZHMgdG8gcmVhc29uIHRoYXQgd2l0aGluLXN1YmplY3QgY2VsbHMgd2lsbCBoYXZlIHNpbWlsYXIgY29ycmVsYXRpb25zLiAKCmBgYHtyfQpsdW5nX2NvdW50cyA8LSBhcy5tYXRyaXgodChsdW5nQGFzc2F5c0BkYXRhJGNvdW50cykpWywgdG9wMmtfaHZnc1sxOjEwMF1dCmdlbmVfc3RhdHMgPC0gdGVzdER5bmFtaWMoZXhwci5tYXQgPSBsdW5nX2NvdW50cywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgcHQgPSBwdF9kZiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgaXMuZ2VlID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgaWQudmVjID0gbHVuZyRQYXRpZW50LCAKICAgICAgICAgICAgICAgICAgICAgICAgICBjb3Iuc3RydWN0dXJlID0gImV4Y2hhbmdlYWJsZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgIG4ucG90ZW50aWFsLmJhc2lzLmZucyA9IDQsIAogICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFsbGVsLmV4ZWMgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBuLmNvcmVzID0gNiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgdHJhY2sudGltZSA9IFRSVUUpCmBgYAoKTGV0J3MgY2hlY2sgb3V0IHRoZSByZXN1bHRzIG9mIHRoZSBnbG9iYWwgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gdGVzdC4gCgpgYGB7cn0KZ2V0UmVzdWx0c0RFKGdlbmVfc3RhdHMpICU+JSAKICBzZWxlY3QoLWNvbnRhaW5zKCJMb2dMaWsiKSwgLWNvbnRhaW5zKCJEZXYiKSkgJT4lICAjIG5vdCByZWxldmFudCB0byBHRUVzCiAgYXJyYW5nZShHZW5lLCBMaW5lYWdlKSAlPiUgCiAgc2xpY2VfaGVhZChuID0gMTApICU+JSAKICBrYWJsZUV4dHJhOjprYmwoZGlnaXRzID0gNSwgCiAgICAgICAgICAgICAgICAgIGFsaWduID0gImMiLCAKICAgICAgICAgICAgICAgICAgYm9va3RhYnMgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgY2FwdGlvbiA9ICJMaW5lYWdlLWxldmVsIGR5bmFtaWMgdGVzdCIsIAogICAgICAgICAgICAgICAgICBjb2wubmFtZXMgPSBjKCJHZW5lIiwgIkxpbmVhZ2UiLCAiVGVzdCBTdGF0LiIsICJQLXZhbHVlIiwgIlRlc3QgU3RhdC4gVHlwZSIsICJUZXN0IE5vdGVzIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1vZGVsIFN0YXR1cyIsICJBZGouIFAtdmFsdWUiLCAiR2VuZSBEeW5hbWljIG92ZXIgTGluZWFnZSIsICJHZW5lIER5bmFtaWMiKSkgJT4lIAogIGthYmxlRXh0cmE6OmthYmxlX3BhcGVyKCJob3ZlciIsIGZ1bGxfd2lkdGggPSBGQUxTRSkKYGBgCgojIyBTbG9wZSBUZXN0IAoKTmV4dCB3ZSBjYW4gcnVuIHRoZSBzbG9wZSB0ZXN0IHRvIGlkZW50aWZ5IG92ZXIgd2hpY2ggcHNldWRvdGltZSBpbnRlcnZhbHMgZ2VuZSBleHByZXNzaW9uIGNoYW5nZXMgc2lnbmlmaWNhbnRseS4gCgpgYGB7cn0KdGVzdFNsb3BlKHRlc3QuZHluLnJlc3VsdHMgPSBnZW5lX3N0YXRzKSAlPiUgCiAgc2xpY2VfaGVhZChuID0gMTApICU+JSAKICBrYWJsZUV4dHJhOjprYmwoZGlnaXRzID0gNSwgCiAgICAgICAgICAgICAgICAgIGFsaWduID0gImMiLCAKICAgICAgICAgICAgICAgICAgYm9va3RhYnMgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgY2FwdGlvbiA9ICJTbG9wZS1sZXZlbCBkeW5hbWljIHRlc3QiLCAKICAgICAgICAgICAgICAgICAgY29sLm5hbWVzID0gYygiR2VuZSIsICJMaW5lYWdlIiwgIkJyZWFrcG9pbnQiLCAiUm91bmRlZCBCcmVha3BvaW50IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkRpcmVjdGlvbiIsICJQLXZhbHVlIiwgIk5vdGVzIiwgIkFkai4gUC12YWx1ZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHZW5lIER5bmFtaWMgb3ZlciBMaW5lYWdlLVNsb3BlIiwgIkdlbmUgRHluYW1pYyBvdmVyIExpbmVhZ2UiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiR2VuZSBEeW5hbWljIikpICU+JSAKICBrYWJsZUV4dHJhOjprYWJsZV9wYXBlcigiaG92ZXIiLCBmdWxsX3dpZHRoID0gRkFMU0UpCmBgYAoKIyMgTW9kZWwgVmlzdWFsaXphdGlvbiAKCkxhc3RseSwgd2UgY2FuIHBsb3QgdGhlIGZpdHRlZCBtb2RlbHMgZm9yIGEgY291cGxlIG9mIHRoZSBnZW5lcy4gSW4gYWRkaXRpb24gdG8gdGhlIG51bGwgKGludGVyY2VwdC1vbmx5KSBhbmQgYE1BUkdFYCBtb2RlbHMgd2UgY2FuIGFsc28gY29tcGFyZSB0byBhIEdFRSBHTE0gd2l0aCBwc2V1ZG90aW1lIGFzIGEgY292YXJpYXRlLiAKCmBgYHtyLCBmaWcud2lkdGg9Nn0KcGxvdE1vZGVscyh0ZXN0LmR5bi5yZXMgPSBnZW5lX3N0YXRzLCAKICAgICAgICAgICBnZW5lID0gIkNYQ0w4IiwgCiAgICAgICAgICAgcHQgPSBwdF9kZiwgCiAgICAgICAgICAgZ2VuZS5jb3VudHMgPSBsdW5nX2NvdW50cywgCiAgICAgICAgICAgaXMuZ2VlID0gVFJVRSwgCiAgICAgICAgICAgaWQudmVjID0gbHVuZyRQYXRpZW50LCAKICAgICAgICAgICBjb3Iuc3RydWN0dXJlID0gImV4Y2hhbmdlYWJsZSIpCnBsb3RNb2RlbHModGVzdC5keW4ucmVzID0gZ2VuZV9zdGF0cywgCiAgICAgICAgICAgZ2VuZSA9ICJSR1MyIiwgCiAgICAgICAgICAgcHQgPSBwdF9kZiwgCiAgICAgICAgICAgZ2VuZS5jb3VudHMgPSBsdW5nX2NvdW50cywgCiAgICAgICAgICAgaXMuZ2VlID0gVFJVRSwgCiAgICAgICAgICAgaWQudmVjID0gbHVuZyRQYXRpZW50LCAKICAgICAgICAgICBjb3Iuc3RydWN0dXJlID0gImV4Y2hhbmdlYWJsZSIpCmBgYAoKIyMgR2VuZS1sZXZlbCBBbmFseXNpcyAKCkxldCdzIGNsdXN0ZXIgdGhlIGdlbmVzIGJhc2VkIG9uIHRoZWlyIGZpdHRlZCB2YWx1ZXMgdXNpbmcgaGllcmFyY2hpY2FsIGNsdXN0ZXJpbmcgd2l0aCBXYXJkJ3MgbGlua2FnZS4gCgpgYGB7ciwgZmlnLndpZHRoPTl9CnB1cnJyOjptYXAoZ2VuZV9zdGF0cywgZnVuY3Rpb24oeCkgewogIGlmIChzdHJpbmdyOjpzdHJfZGV0ZWN0KHgkTGluZWFnZV9BJE1vZGVsX1N0YXR1cywgImVycm9yIikpIHsKICAgIE5BCiAgfSBlbHNlIHsKICAgIHgkTGluZWFnZV9BJE1BUkdFX1ByZWRzJG1hcmdlX2xpbmtfZml0CiAgfQp9KSAlPiUgCiAgcHVycnI6OnJlZHVjZShjYmluZCkgJT4lIAogIHNldF9jb2xuYW1lcyhuYW1lcyhnZW5lX3N0YXRzKSkgJT4lIAogICNzZXRfcm93bmFtZXMocm93bmFtZXMobHVuZ19jb3VudHMpKSAlPiUgCiAgamFuaXRvcjo6cmVtb3ZlX2VtcHR5KHdoaWNoID0gImNvbHMiKSAtPiBmaXR0ZWRfdmFscwpmaXR0ZWRfdmFsc19wY2EgPC0gcHJjb21wKHQoZml0dGVkX3ZhbHMpLCBjZW50ZXIgPSBUUlVFLCByYW5rLiA9IDEwKSR4CmZpdHRlZF92YWxzX2NsdXN0cyA8LSBoY2x1c3QoZGlzdChmaXR0ZWRfdmFsc19wY2EpLCBtZXRob2QgPSAid2FyZC5EMiIpCmdnZGVuZHJvOjpnZ2RlbmRyb2dyYW0oZml0dGVkX3ZhbHNfY2x1c3RzKSArIAogIGxhYnModGl0bGUgPSAiSGVpcmFyY2hpY2FsIENsdXN0ZXJpbmcgb2YgSGlnaGx5LVZhcmlhYmxlIEdlbmVzIikgKyAKICB0aGVtZV9jbGFzc2ljKGJhc2Vfc2l6ZSA9IDE0KSArIAogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHNpemUgPSA4KSwgCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksIAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpgYGAKCiMgU2Vzc2lvbiBJbmZvIAoKYGBge3J9CnNlc3Npb25pbmZvOjpzZXNzaW9uX2luZm8oKQpgYGAK